<?php

abstract class Workset_Model_Object_Storage_Abstract {

	protected static $_registry = null;

	protected $_objectClass = null;

	protected $_iteratorClass = null;

	protected $_options = array();

	protected $_throwNullPointerException = true;

	/**
	 * @static
	 * @throws Zend_Exception
	 * @param  $storageClass
	 * @param  $options
	 * @return Workset_Model_Object_Storage_Abstract
	 *
	 * Multiton implementation
	 */
	static function getStatic($storageClass, $options = null) {
		$key = $storageClass;
		if (null !== $options) {
			if (is_array($options)) {
				ksort($options);
			}
			$key .= serialize($options);
		}

        $registry = self::getRegistry();
		if (!isset($registry[$key])) {
			if (!class_exists($storageClass)) {
				throw new Workset_Model_Exception("Undefined class $storageClass");
			}
			
			$storage = new $storageClass();
			if (null !== $options) {
				if (!is_array($options)) {
					$options = array('objectClass' => $options);
				}
				$storage->setOptions($options);
			}

			$registry[$key] = $storage;
		}
		return $registry[$key];
	}

	static function setRegistry(ArrayObject $registry, $key = null) {
        if (null !== $key) {
            if (!array_key_exists($key, $registry)) {
                $registry[$key] = array();
            }
            self::$_registry = & $registry[$key];
        } else {
            self::$_registry = $registry;
        }
    }

    static function getRegistry() {
        if (null === self::$_registry) {
           self::$_registry = new ArrayObject();
        }
        return self::$_registry;
    }

	function __construct($options = null) {
		if (null !== $options) {
			$this->setOptions($options);
		}
		$this->init();
	}

	/**
	 * Переопределяется в наследниках
	 *
	 * @return void
	 */
	function init() {}

	function setObjectClass($class) {
		if (!class_exists($class)) {
			throw new Workset_Model_Exception("Undefined class $class");
		}
		$this->_objectClass = $class;
		return $this;
	}

	function setIteratorClass($class) {
		if (!class_exists($class)) {
			throw new Workset_Model_Exception("Undefined class $class");
		}
		$this->_iteratorClass = $class;
		return $this;
	}

	function setOptions(array $options) {
		if (!$this->_options) {
			$this->_options = $options;
		} else {
			$this->_options = array_merge($this->_options, $options);
		}

		foreach ($this->_options as $key => $option) {
			switch ($key) {
				case 'objectClass':
					$this->setObjectClass($option);
					unset($this->_options[$key]);
				break;

				case 'iteratorClass':
					$this->setObjectIteratorClass($option);
					unset($this->_options[$key]);
				break;

				case 'throwNullPointerException':
					$this->setThrowNullPointerException($option);
					unset($this->_options[$key]);
				break;
			}
		}

		return $this;
	}

	function setThrowNullPointerException($flag) {
		$this->_throwNullPointerException = (boolean)$flag;
	}

	function throwNullPointerException() {
		return $this->_throwNullPointerException;
	}

	function getIterator($items, $options = null) {
		$objectClass = $this->_objectClass;
		$iteratorClass = $this->_iteratorClass;
		$storage = $this;

		if (is_array($options)) {
			if (isset($options['objectClass'])) {
				$objectClass = $options['objectClass'];
			}

			if (isset($options['iteratorClass'])) {
				$iteratorClass = $options['iteratorClass'];
			}

			if (array_key_exists('storage', $options)) {
				$storage = $options['storage'];
			}
		}

		$iterator = new $iteratorClass($items);
		if (!$iterator instanceof Workset_Model_Object_Iterator_Abstract) {
			throw new Workset_Model_Exception("Invalid iterator type {$this->_iteratorClass}");
		}

		$iterator->setObjectClass($objectClass)
				 ->setObjectOptions(array(
					'storage' => $storage
				 ));

		return $iterator;
	}

	function getCacheId($key = null) {
		if (null === $key) {
			$key = '';
		} elseif (is_array($key)) {
			ksort($key);
			$key = serialize($key);
		} else {
			$key = (string)$key;
		}

		$key .= get_class($this);

		return $key;
	}

	abstract function create($data);

	abstract function save(Workset_Model_Object_Interface $object, $data = null);

	abstract function delete(Workset_Model_Object_Interface $object);

	abstract function getOne($identity);

	abstract function getAll();

    abstract function beginTransaction();

    abstract function commit();

    abstract function rollBack();

}

?>